package com.wang.tool.monitor.core;

import com.wang.tool.monitor.LinkLogUtil;
import com.wang.tool.monitor.fastover.FastoverInfo;
import com.wang.tool.monitor.ops.MonitorOps;
import com.wang.tool.monitor.ops.MonitorOpsCenter;
import com.wang.tool.monitor.template.MonitorInvoker;
import com.wang.tool.monitor.weaver.MonitorWeaver;
import com.wang.tool.common.ErrorInfo;

import java.util.Map;

/**
 * 范式api暴露
 * Monitor同包,将非public函数暴露给使用方用以组装切面/模板
 * 抽离了常用调用范式,可以编排自己的服务模板
 * 1.同步 stepIn  and  stepOut
 * 2.异步 stepInAsync and stepOutAsync
 * 3.后补 独立fastover and recordLink
 *
 * @Description monitorApi
 * @Author shaopeng
 * @Date 2022/10/21
 * @Version 1.0
 */
public class MonitorApi {


    /**
     * 尝试步入并创建监控基础信息
     * 有入必有出
     *
     * @param <R>
     * @param group     非空
     * @param biz       非空
     * @param action    非空
     * @param params    入参
     * @param beginTime 开始时间
     * @return 非空
     * @see MonitorApi#stepOutMonitor
     */
    public static <R> MonitorInfo<R> stepInMonitor(String group, String biz, String action, MonitorWeaver<R> weaver, Object[] params, long beginTime) {
        try {
            return new MonitorInfo<>(group, biz, action, weaver, params, beginTime, false);
        } catch (Throwable e) {
            LinkLogUtil.newTagLog(MonitorInfo.TAG_MONITOR_ERROR)
                    .v1(biz + ":" + action)
                    .v2("stepInMonitor")
                    .addAttachment(MonitorInfo.ERROR, e)
                    .log();
            return null;
        }
    }

    /**
     * 尝试步出
     * 有入必有出
     *
     * @param monitorInfo
     * @param result
     * @param error
     * @param endTime
     * @see MonitorApi#stepInMonitor
     */
    public static <R> void stepOutMonitor(MonitorInfo<R> monitorInfo, R result, ErrorInfo error, long endTime) {
        if (monitorInfo == null) {
            return;
        }
        monitorInfo.stepOutMonitor(result, error, endTime, false);
    }



    /*-----------------分割线----------------*/

    /**
     * 创建异步Monitor
     *
     * @param <R>
     * @param group     非空
     * @param biz       非空
     * @param action    非空
     * @param params    入参
     * @param beginTime 开始时间
     * @return 非空
     * @see MonitorApi#stepOutMonitor
     */
    public static <R> MonitorInfo<R> stepInMonitorAsync(String group, String biz, String action, MonitorWeaver<R> weaver, Object[] params, long beginTime) {
        try {
            return new MonitorInfo<>(group, biz, action, weaver, params, beginTime, true);
        } catch (Throwable e) {
            LinkLogUtil.newTagLog(MonitorInfo.TAG_MONITOR_ERROR)
                    .v1(biz + ":" + action)
                    .v2("stepInMonitor")
                    .addAttachment(MonitorInfo.ERROR, e)
                    .log();
            return null;
        }
    }


    /**
     * 尝试步出
     *
     * @param monitorInfo
     * @param result
     * @param error
     * @param endTime
     * @see MonitorApi#stepInMonitor
     */
    public static <R> void stepOutMonitorAsync(MonitorInfo<R> monitorInfo, R result, ErrorInfo error, long endTime) {
        if (monitorInfo == null) {
            return;
        }
        //防止上层代码有误导致,一次请求多次输出
        Map<String, Object> details = monitorInfo.getDetails();
        if (details != null && details.get("_async_") != null) {
            return;
        }
        monitorInfo.addShortDetail("_async_", true);
        monitorInfo.stepOutMonitor(result, error, endTime, true);
    }



    /*-----------------分割线----------------*/

    /**
     * 获取业务快速结束信息
     *
     * @param group
     * @param biz    非空
     * @param action 非空
     * @param time   非空
     * @param params
     * @return
     */
    public static FastoverInfo fastover(String group, String biz, String action, long time, Object[] params) {
        MonitorOps ops = MonitorOpsCenter.getOps(group, biz, action, time);
        try {
            return ops == null ? null : ops.fastover(time, params);
        } catch (Throwable e) {
            LinkLogUtil.newTagLog(MonitorInfo.TAG_MONITOR_ERROR)
                    .v1(biz + ":" + action)
                    .v2("onlyOpsFastover")
                    .addAttachment(MonitorInfo.ERROR, e)
                    .log();
            return null;
        }
    }


    /**
     * 手动记录链路 并输出摘要
     *
     * @param parent    指定父节点,不会使用当前线程变量
     * @param group     尽量非空
     * @param biz       尽量非空
     * @param action    尽量非空
     * @param beginTime 非空
     * @param params    如实
     * @param endTime   非空
     * @param result    如实
     * @param error     如实
     * @param weaver    如实
     * @param <R>
     * @return
     */
    public static <R> MonitorInfo<R> recordLink(LinkInfo parent, String group, String biz, String action, long beginTime, Object[] params, long endTime, R result, ErrorInfo error, MonitorWeaver<R> weaver) {
        try {
            group = group != null ? group : "";
            biz = biz != null ? biz : "";
            action = action != null ? action : "";
            params = params == null ? MonitorInvoker.EMPTY_PARAM : params;

            return new MonitorInfo<>(parent, group, biz, action, beginTime, params, endTime, result, error, weaver);
        } catch (Throwable e) {
            LinkLogUtil.newTagLog(MonitorInfo.TAG_MONITOR_ERROR)
                    .v1(biz + ":" + action)
                    .v2("recordLink")
                    .pointLink(parent)
                    .addAttachment(MonitorInfo.ERROR, e)
                    .log();
            return null;
        }
    }
}
